// 《围棋》作者版权所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package runtime

import (
	"internal/abi"
	"internal/goarch"
	"unsafe"
)

// libc函数包装器。必须在系统堆栈上运行。英国政府的第二次外国政府的第二次外国政府的第二次外国政府的第二次外国政府的第二次外国政府的第二次外国政府的第二次外国政府的第二次外国政府的第三次外国政府的第三次外国政府的第三次外国政府的第五次外国政府的第五次外国政府的第五次外国政府的第三次外国政府的第三次外国政府的第三次外国政府的第三次外国政府的第三次外国政府的第三次外国政府的第三次外国政府政府的第三次外国政府的第三次外国政府的第三次外国政府的第三次外国政府的政府的政府的第三次政府的第三次政府的政府的第三次政府的第三次政府的政府的政府的第三次政府的第三次政府的政府的政府的第三次外国政府的政府的第三次政府的政府的政府的第三次政府的第三次政府的政府的政府的第三次政府的第三次政府的第三ag的线程本地存储插槽。

func g0_pthread_key_create(k *pthreadkey, destructor uintptr) int32 {
	ret := asmcgocall(unsafe.Pointer(abi.FuncPCABI0(pthread_key_create_trampoline)), unsafe.Pointer(&k))
	KeepAlive(k)
	return ret
}
func pthread_key_create_trampoline()

func g0_pthread_setspecific(k pthreadkey, value uintptr) int32 {
	return asmcgocall(unsafe.Pointer(abi.FuncPCABI0(pthread_setspecific_trampoline)), unsafe.Pointer(&k))
}
func pthread_setspecific_trampoline()


// 
// 它使用pthread_key_create查找第一个可用插槽，并使用
// 它作为运行时的偏移值。tlsg。
// 
// 它在g0堆栈上启动时运行，但在设置g之前，所以它必须
// 不拆分堆栈（传递）。g预计为零，因此事物
// （例如asmcgocall）将跳过保存或读取g。
// 
// go:nosplit 
func tlsinit(tlsg *uintptr, tlsbase *[_PTHREAD_KEYS_MAX]uintptr) {
	var k pthreadkey
	err := g0_pthread_key_create(&k, 0)
	if err != 0 {
		abort()
	}

	const magic = 0xc476c475c47957
	err = g0_pthread_setspecific(k, magic)
	if err != 0 {
		abort()
	}

	for i, x := range tlsbase {
		if x == magic {
			*tlsg = uintptr(i * goarch.PtrSize)
			g0_pthread_setspecific(k, 0)
			return
		}
	}
	abort()
}
